# Copyright (c) 2018 Open Source Foundries Limited.
# Copyright 2019 Foundries.io
# Copyright (c) 2020 Nordic Semiconductor ASA
#
# SPDX-License-Identifier: Apache-2.0

# 要求二进制文件必须在应用目录下

'''west "stlink" command'''
import os
import colorama
from textwrap import dedent            # just for nicer code indentation
from pathlib import Path
from west.commands import WestCommand
from west.configuration import config
from west import log
import subprocess
import zcmake
from build_helpers import find_build_dir, is_zephyr_build, \
    FIND_BUILD_DIR_DESCRIPTION

class Stlink(WestCommand):

    def __init__(self):
        super(Stlink, self).__init__(
            'stlink',
            # Keep this in sync with the string in west-commands.yml.
            'stlink and run a binary on a board',
            dedent("Permanently reprogram a board's flash with a new bin file (address)."),
            accepts_unknown_args=True)
        self.filename = None
        self.address = "0x8000000"
    def do_add_parser(self, parser_adder):
        parser = parser_adder.add_parser(self.name,
                                        help=self.help,
                                        description=self.description)
        # 需要下载和编译的文件
        parser.add_argument('-n', '--filename', help='bin filename')
        # 需要下载的文件地址
        parser.add_argument('-a','--address', help='bin address')
        return parser
    
    def do_run(self, args, unknown_args):
        if args.filename is None:
            raise RuntimeError(
                'filename is None;use -n filename')
        if args.address is not None:
            self.address = args.address
        
        self.filename = args.filename
        build_dir = find_build_dir(None)
        if build_dir and is_zephyr_build(build_dir):
            cache = load_cmake_cache(build_dir)
            board_dir= cache['BOARD_DIR']
            app_dir=cache['APPLICATION_SOURCE_DIR']
            pathfiename = os.path.join(app_dir,self.filename)
            if not os.path.exists(pathfiename):
                raise RuntimeError('filename path is not')
            openocdconfig = os.path.join(board_dir, 'support', 'openocd.cfg')
            if not os.path.exists(openocdconfig):
                raise RuntimeError('openocd.cfg is not')
            search_args = ['-s', os.path.dirname(openocdconfig)]
            config = ['-f',openocdconfig]
            cmd=(["openocd.exe"]+search_args+config+['-c', 'init',
                                '-c', 'targets']+['-c', 'reset halt',
                                '-c','program ' + pathfiename +' '+self.address+' verify reset exit'])
            #log.dbg("cmd:",cmd)
            openocd_excute = subprocess.Popen(cmd,stdout=subprocess.PIPE,bufsize=200,universal_newlines=True)
            for msg in iter(openocd_excute.stdout.readline,''):
                 log.msg(msg,color=colorama.Fore.GREEN)
        else:
            raise RuntimeError(
                'path is not zephyr app')

# 加载cmake
def load_cmake_cache(build_dir):
    cache_file = os.path.join(build_dir, zcmake.DEFAULT_CACHE)
    try:
        return zcmake.CMakeCache(cache_file)
    except FileNotFoundError:
        log.die(f'no CMake cache found (expected one at {cache_file})')
